import { AppLogger } from '@/logger/logger.service';
import {
  ArgumentsHost,
  BadRequestException,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
  UnauthorizedException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';

import { BizException } from '../exceptions/biz.exception';
import { TreadstoneService } from '../services/treadstone.service';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  constructor(
    private readonly logger: AppLogger,
    private readonly treadstone: TreadstoneService,
  ) {}
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = exception.message;
    if (exception instanceof HttpException) {
      status = exception.getStatus();
    }
    if (exception instanceof BadRequestException) {
      const exceptionResponse = exception.getResponse();
      status = exception.getStatus();

      // 处理错误消息拼接
      let errorMessages: string[] = [];
      if (typeof exceptionResponse === 'object' && exceptionResponse['message']) {
        const messages = exceptionResponse['message'];
        if (Array.isArray(messages)) {
          errorMessages = messages.map((msg) => {
            if (typeof msg === 'string') return msg; // 直接字符串错误
            if (typeof msg === 'object') {
              // 处理 class-validator 返回的对象结构错误
              return Object.values(msg.constraints || {}).join(', ');
            }
            return String(msg);
          });
        }
      }
      message = errorMessages.length > 0 ? errorMessages.join('; ') : '请求参数错误';
    }
    const result = {
      code: status,
      timestamp: new Date().toLocaleString(),
      path: request.url,
      message,
    };

    // 已知请求错误（如唯一约束、外键冲突）
    if (exception instanceof Prisma.PrismaClientKnownRequestError) {
      if (exception.code === 'P2002') {
        Object.assign(result, {
          code: HttpStatus.CONFLICT,
          errorCode: 'UNIQUE_CONSTRAINT_FAILED',
          message: `数据已存在，请勿重复创建`,
        });
      } else if (exception.code === 'P2025') {
        Object.assign(result, {
          code: HttpStatus.NOT_FOUND,
          errorCode: 'RECORD_NOT_FOUND',
          message: '请求的资源不存在',
        });
      } else {
        Object.assign(result, {
          code: HttpStatus.BAD_REQUEST,
          errorCode: 'DATABASE_ERROR',
          message: '数据库操作失败',
        });
      }
    }

    // 参数校验错误（如字段类型错误）
    if (exception instanceof Prisma.PrismaClientValidationError) {
      Object.assign(result, {
        code: HttpStatus.BAD_REQUEST,
        errorCode: 'VALIDATION_ERROR',
        message: '请求参数不合法',
      });
    }
    const logData = {
      status,
      url: request.url,
      method: request.method,
      timestamp: new Date().toISOString(),
      message: exception instanceof Error ? exception.message : 'Unknown error',
    };
    const exceptionData = {
      path: request.url,
      method: request.method,
      name: exception.name,
      level: 'warn',
      code: exception.code || 'ERROR',
      status,
      message: exception.message,
      stack: exception.stack,
      creatorId: request.user?.serial,
      creatorName: request.user?.name,
      payload: request.body,
    };
    if (!(exception instanceof BizException) && !(exception instanceof UnauthorizedException)) {
      Object.assign(logData, { stack: exception instanceof Error ? exception.stack : undefined });
      Object.assign(exceptionData, { level: 'error' });
      this.treadstone.createException(exceptionData);
    }
    this.logger.error(logData);
    response.status(HttpStatus.OK).json(result);
  }
}
